package com.millstein.mq;

import com.millstein.model.OrderMessage;
import com.millstein.service.ProductOrderService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @description:
 * @author: tsing
 * @create: 2021-09-24 19:40
 */
@Component
@Slf4j
@RabbitListener(queues = "${mqconfig.order-close-queue}")
public class OrderCloseListener {

    @Autowired
    private ProductOrderService productOrderService;

    @RabbitHandler
    public void closeOrder(OrderMessage orderMessage, Message message, Channel channel) {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            boolean retry = productOrderService.doCloseOrder(orderMessage);
            doAfterCloseByRetry(deliveryTag, retry, channel, orderMessage);
        } catch (Exception e) {
            doAfterCloseWhileOccurredException(channel, deliveryTag, e, orderMessage);

        }
    }

    private void doAfterCloseWhileOccurredException(Channel channel, long deliveryTag, Exception e, OrderMessage orderMessage) {
        try {
            log.error("处理关单消息时失败，{}", e.getMessage(), e);
            channel.basicReject(deliveryTag, true);
        } catch (Exception ex) {
            // TODO 这里可以直接写入数据库，等待人工核查
            log.error("异常处理失败：{}，原因是：{}", orderMessage, ex.getMessage(), ex);
        }

    }

    /**
     * 根据是否需要重新投递，来进行后续操作
     * @param deliveryTag 消息标识
     * @param retry 是否需要重试
     * @param channel 通道
     * @param orderMessage 消息内容
     */
    private void doAfterCloseByRetry(long deliveryTag, boolean retry, Channel channel, OrderMessage orderMessage) throws IOException {
        try {
            if (retry) {
                log.error("关单失败，需要重新投递：{}", orderMessage);
                channel.basicReject(deliveryTag, true);
            } else {
                log.info("关单成功：{}", orderMessage);
                channel.basicAck(deliveryTag, false);
            }
        } catch (Exception e) {
            log.error("处理关单消息时失败，{}", orderMessage);
            channel.basicReject(deliveryTag, true);
        }
    }
}
